home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / graphics / conversion / giftrans / giftrans.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-20  |  26.5 KB  |  977 lines

  1. /*
  2. ** GIFtrans v1.12.1
  3. **
  4. ** Convert any GIF file into a GIF89a
  5. ** Allows for setting the transparent or background color, changing colors,
  6. ** adding or removing comments. Also code to analyze GIF contents.
  7. **
  8. ** Copyright (c) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
  9. ** Amiga GNU C support 9.4.96 by Brian D. Switzer <bswitzer@uoguelph.ca>
  10. **
  11. ** Permission to use, copy, modify, and distribute this software for any
  12. ** purpose and without fee is hereby granted, provided that the above
  13. ** copyright notice appears in all copies. This software is provided "as is"
  14. ** and without any express or implied warranties.
  15. **
  16. ** This program has been tested on a HP9000/715 with HP-UX A.09.05
  17. ** In this environment, neither lint -u nor gcc -Wall produce any messages.
  18. ** It has also been compiled on AIX 3.2 and Solaris 2.3.
  19. ** If you encounter any errors or need to make any changes to port it
  20. ** to another platform, please contact me.
  21. **
  22. ** Known bugs:
  23. **    -B flag won't work if there's an Extension between the Global Color
  24. **    Table and the Image Descriptor (or Graphic Control Extension). If -V
  25. **    has been specified, a Warning Message will be displayed.
  26. **    Will be fixed in 2.0 (if ever)
  27. **    -D option may output changed data instead of original data, use
  28. **    with caution, best only with then -L option.
  29. **
  30. ** Version history
  31. **
  32. ** Version 1.12.1 - 9.2.96
  33. **    Fix for multi-word color names.
  34. **
  35. ** Version 1.12 - 17.2.95
  36. **    Incorporated dumpcomment by omerzu@quantum.de (Thomas Omerzu)
  37. **    Outputs original version if newer than GIF89a.
  38. **
  39. ** Version 1.11.2 - 14.12.94
  40. **    Incorporated OS/2 port by k.rusch@ieee.org (Klaus Johannes Rusch)
  41. **    Different rgb.txt file for OS/2, setmode replaced by freopen for
  42. **    OS/2 (SAA C) 
  43. **
  44. ** Version 1.11.1 - 11.8.94
  45. **    Allows for use of the -g option without the -B option.
  46. **
  47. ** Version 1.11 - 21.7.94
  48. **    Moved Plain Text Extension to the Extensions section where it belongs.
  49. **    Accept Unknown Extension Labels.
  50. **    Incorporated MS-DOS port by enzo@hk.net (Enzo Michelangeli).
  51. **    Added -o and -e options to redirect stdout and stderr.
  52. **    Added -D debug flag.
  53. **
  54. ** Version 1.10.2 - 22.6.94
  55. **    Support for -DRGBTXT flag.
  56. **
  57. ** Version 1.10.1 - 21.6.94
  58. **    Different rgb.txt file FreeBSD/386BSD.
  59. **
  60. ** Version 1.10 - 19.6.94
  61. **    Added -g option to change a color in the global color table.
  62. **    Added -B option to change the color for the transparent color index.
  63. **
  64. ** Version 1.9.1 - 7.6.94
  65. **    Different rgb.txt files for X11 and Open Windows.
  66. **
  67. ** Version 1.9 - 1.6.94
  68. **    Fixed a bug which caused color names to be rejected.
  69. **
  70. ** Version 1.8 - 30.5.94
  71. **    Accept #rrggbb style arguments.
  72. **    Do nothing if rgb-color not found in GIF.
  73. **
  74. ** Version 1.7 - 16.5.94
  75. **    Added -l option to only list the color table.
  76. **    Added -L option for verbose output without creating a gif.
  77. **    Added -b option to change the background color index.
  78. **    Display all matching color names for color table entries.
  79. **    Fixed a bug which caused bad color names if rgb.txt starts with
  80. **        whitespace.
  81. **    Doesn't use strdup anymore.
  82. **    Fixed =& bug on dec machines.
  83. **
  84. ** Version 1.6 - 5.4.94
  85. **    Added color names recognition.
  86. **
  87. ** Version 1.5 - 15.3.94
  88. **    Added basic verbose output to analyze GIFs.
  89. **
  90. ** Version 1.4 - 8.3.94
  91. **    Fixed off-by-one bug in Local Color table code.
  92. **    Added -c and -C options to add or remove a comment.
  93. **    Transparency is no longer the default.
  94. **
  95. ** Thanx for bug reports, ideas and fixes to
  96. **    patricka@cs.kun.nl (Patrick Atoon)
  97. **    wes@msc.edu (Wes Barris)
  98. **    pmfitzge@ingr.com (Patrick M. Fitzgerald)
  99. **    hoesel@chem.rug.nl (Frans van Hoesel)
  100. **    boardman@jerry.sal.wisc.edu (Dan Boardman)
  101. **    krweiss@chip.ucdavis.edu (Ken Weiss)
  102. **    chuck.musciano@harris.com (Chuck Musciano)
  103. **    heycke@camis.stanford.edu (Torsten Heycke)
  104. **    claw@spacsun.rice.edu (Colin Law)
  105. **    jwalker@eos.ncsu.edu (Joseph C. Walker)
  106. **    Bjorn.Borud@alkymi.unit.no (Bjorn Borud)
  107. **    Christopher.Vance@adfa.oz.au (CJS Vance)
  108. **    pederl@norway.hp.com (Peder Langlo)
  109. **    I.Rutson@bradford.ac.uk (Ian Rutson)
  110. **    Nicolas.Pioch@enst.fr (Nicolas Pioch)
  111. **    john@charles.CS.UNLV.EDU (John Kilburg)
  112. **    enzo@hk.net (Enzo Michelangeli)
  113. **    twv@hpwtwe0.cup.hp.com (Terry von Gease)
  114. **    k.rusch@ieee.org (Klaus Johannes Rusch)
  115. **    omerzu@quantum.de (Thomas Omerzu)
  116. **    Willem.Vermin@sara.nl (Willem Vermin)
  117. **    wjones@tc.fluke.COM (Warren Jones)
  118. **
  119. ** Original distribution site is
  120. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c
  121. ** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
  122. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1
  123. ** An online version by taylor@intuitive.com (Dave Taylor) is at
  124. **       http://www.intuitive.com/coolweb/Addons/giftrans-doc.html
  125. ** To compile for MS-DOS or OS/2, you need getopt:
  126. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c
  127. ** MS-DOS executable can be found at
  128. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe
  129. ** OS/2 executable can be found at
  130. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe
  131. ** A template rgb.txt for use with the MS-DOS version can be found at
  132. **    ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt
  133. ** Additional info can be found on
  134. **    http://melmac.corp.harris.com/transparent_images.html
  135. ** The GIF file format is documented in
  136. **    ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
  137. */
  138.  
  139. #define AMIGAGCC    /* When using GNU C on Amiga */
  140. #undef    X11        /* When using X Window System */
  141. #undef    OPENWIN        /* When using Open Windows */
  142. #undef    X386        /* When using XFree86 with FreeBSD/386BSD */
  143. #undef    OS2        /* When using IBM C/C++ 2.0 */
  144. #ifndef    MSDOS    /* required for TurboC 1.0 */
  145. #undef    MSDOS        /* When using Borland C (maybe MSC too) */
  146. #endif
  147.  
  148. #ifndef OS2_OR_MSDOS
  149. #ifdef OS2
  150. #define OS2_OR_MSDOS
  151. #endif /* OS2 */
  152. #ifdef MSDOS
  153. #define OS2_OR_MSDOS
  154. #endif /* MSDOS */
  155. #endif /* OS2_OR_MSDOS */
  156.  
  157. char copyright[] = "@(#)(c) Copyright 1994 by Andreas Ley (ley@rz.uni-karlsruhe.de)\nAmiga GNU C support 9.4.96 by Brian D. Switzer (bswitzer@uoguelph.ca)\n";
  158. char sccsid[] = "@(#)GIFtrans v1.12.1.[BDS] - Transpose GIF files";
  159.  
  160. #ifndef RGBTXT
  161. #ifdef AMIGAGCC
  162. #define RGBTXT  "S:rgb.txt"
  163. #else /* AMIGAGCC */
  164. #ifdef X11
  165. #define    RGBTXT    "/usr/lib/X11/rgb.txt"
  166. #else /* X11 */
  167. #ifdef OPENWIN
  168. #define    RGBTXT    "/usr/openwin/lib/rgb.txt"
  169. #else /* OPENWIN */
  170. #ifdef X386
  171. #define    RGBTXT    "/usr/X386/lib/X11/rgb.txt"
  172. #else /* X386 */
  173. #ifdef OS2_OR_MSDOS
  174. #define    RGBTXT    "rgb.txt"
  175. #else /* OS2_OR_MSDOS */
  176. #define    RGBTXT    "";
  177. #endif /* OS2_OR_MSDOS */
  178. #endif /* X386 */
  179. #endif /* OPENWIN */
  180. #endif /* X11 */
  181. #endif /* AMIGAGCC */
  182. #endif /* RGBTXT */
  183.  
  184. #include <stdlib.h>
  185. #include <stdio.h>
  186. #include <string.h>
  187. #include <errno.h>
  188. #ifndef OS2_OR_MSDOS
  189. #include <unistd.h>
  190. #include <ctype.h>
  191. #include <sys/param.h>
  192. #else /* OS2_OR_MSDOS */
  193. #include <fcntl.h>
  194. #ifdef OS2
  195. #include <io.h>
  196. #endif /* OS2 */
  197. #include "getopt.c"
  198. #endif /* OS2_OR_MSDOS */
  199.  
  200. #ifndef MAXPATHLEN
  201. #define MAXPATHLEN 256
  202. #endif /* MAXPATHLEN */
  203.  
  204. #ifndef FALSE
  205. #define    FALSE    (0)        /* This is the naked Truth */
  206. #define    TRUE    (1)        /* and this is the Light */
  207. #endif
  208.  
  209. #define    SUCCESS    (0)
  210. #define    FAILURE    (1)
  211.  
  212. struct entry {
  213.     struct entry    *next;
  214.     char        *name;
  215.     int        red;
  216.     int        green;
  217.     int        blue;
  218.     } *root;
  219.  
  220. #define    NONE    (-1)
  221. #define    OTHER    (-2)
  222. #define    RGB    (-3)
  223.  
  224. struct color {
  225.     int        index;
  226.     int        red;
  227.     int        green;
  228.     int        blue;
  229.     } bc,tc,tn,go,gn;
  230.  
  231. static char    *image,*comment;
  232. static int    skipcomment,list,verbose,output,debug;
  233. static long int    pos;
  234.  
  235. static char    rgbtxt[] = RGBTXT, *rgb = rgbtxt;
  236. static char    true[] = "True";
  237. static char    false[] = "False";
  238.  
  239. #define    readword(buffer)    ((buffer)[0]+256*(buffer)[1])
  240. #define    readflag(buffer)    ((buffer)?true:false)
  241. #define    hex(c)            ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
  242.  
  243.  
  244. void dump(adr,data,len)
  245. long int    adr;
  246. unsigned char    *data;
  247. size_t        len;
  248. {
  249.     int    i;
  250.  
  251.     while (len>0) {
  252.         (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
  253.         for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
  254.             (void)fprintf(stderr,"%s%02x",i==8?"  ":" ",*data);
  255.         (void)fprintf(stderr,"\n");
  256.     }
  257. }
  258.  
  259.  
  260.  
  261. void writedata(dest,data,len)
  262. FILE        *dest;
  263. unsigned char    *data;
  264. size_t        len;
  265. {
  266.     unsigned char    size;
  267.  
  268.     while (len) {
  269.         size=len<256?len:255;
  270.         (void)fwrite((void *)&size,1,1,dest);
  271.         (void)fwrite((void *)data,(size_t)size,1,dest);
  272.         data+=size;
  273.         len-=size;
  274.     }
  275.     size=0;
  276.     (void)fwrite((void *)&size,1,1,dest);
  277. }
  278.  
  279.  
  280. void skipdata(src)
  281. FILE    *src;
  282. {
  283.     unsigned char    size,buffer[256];
  284.  
  285.     do {
  286.         pos=ftell(src);
  287.         (void)fread((void *)&size,1,1,src);
  288.         if (debug)
  289.             dump(pos,&size,1);
  290.         if (debug) {
  291.             pos=ftell(src);
  292.             (void)fread((void *)buffer,(size_t)size,1,src);
  293.             dump(pos,buffer,(size_t)size);
  294.         }
  295.         else
  296.             (void)fseek(src,(long int)size,SEEK_CUR);
  297.     } while (!feof(src)&&size>0);
  298. }
  299.  
  300.  
  301. void transblock(src,dest)
  302. FILE    *src;
  303. FILE    *dest;
  304. {
  305.     unsigned char    size,buffer[256];
  306.  
  307.     pos=ftell(src);
  308.     (void)fread((void *)&size,1,1,src);
  309.     if (debug)
  310.         dump(pos,&size,1);
  311.     if (output)
  312.         (void)fwrite((void *)&size,1,1,dest);
  313.     pos=ftell(src);
  314.     (void)fread((void *)buffer,(size_t)size,1,src);
  315.     if (debug)
  316.         dump(pos,buffer,(size_t)size);
  317.     if (output)
  318.         (void)fwrite((void *)buffer,(size_t)size,1,dest);
  319. }
  320.  
  321.  
  322. void dumpcomment(src)
  323. FILE    *src;
  324. {
  325.     unsigned char    size,buffer[256];
  326.     size_t i;
  327.  
  328.     pos=ftell(src);
  329.     (void)fread((void *)&size,1,1,src);
  330.     if (debug)
  331.         dump(pos,&size,1);
  332.     (void)fread((void *)buffer,(size_t)size,1,src);
  333.     if (debug)
  334.         dump(pos+1,buffer,(size_t)size);
  335.     for (i=0; i<(size_t)size; i++)
  336.     {
  337.         if (i%60==0)
  338.             (void)putc('\t',stderr);
  339.         if (isprint(buffer[i]))
  340.             (void)putc(buffer[i],stderr);
  341.         else
  342.             (void)fprintf(stderr,"\\%03o",buffer[i]);
  343.         if (i%60==59)
  344.             (void)putc('\n',stderr);
  345.     }
  346.     if (i%60)
  347.         (void)putc('\n',stderr);
  348.     (void)fseek(src,(long int)pos,SEEK_SET);
  349. }
  350.  
  351.  
  352. void transdata(src,dest)
  353. FILE    *src;
  354. FILE    *dest;
  355. {
  356.     unsigned char    size,buffer[256];
  357.  
  358.     do {
  359.         pos=ftell(src);
  360.         (void)fread((void *)&size,1,1,src);
  361.         if (debug)
  362.             dump(pos,&size,1);
  363.         if (output)
  364.             (void)fwrite((void *)&size,1,1,dest);
  365.         pos=ftell(src);
  366.         (void)fread((void *)buffer,(size_t)size,1,src);
  367.         if (debug)
  368.             dump(pos,buffer,(size_t)size);
  369.         if (output)
  370.             (void)fwrite((void *)buffer,(size_t)size,1,dest);
  371.     } while (!feof(src)&&size>0);
  372. }
  373.  
  374.  
  375. int giftrans(src,dest)
  376. FILE    *src;
  377. FILE    *dest;
  378. {
  379.     unsigned char    buffer[3*256],lsd[7],gct[3*256],gce[5];
  380.     unsigned int    cnt,cols,size,gct_size,gct_delay,gce_present;
  381.     struct entry    *rgbptr;
  382.  
  383.  
  384.     /* Header */
  385.     pos=ftell(src);
  386.     (void)fread((void *)buffer,6,1,src);
  387.     if (strncmp((char *)buffer,"GIF",3)) {
  388.         (void)fprintf(stderr,"No GIF file!\n");
  389.         return(1);
  390.     }
  391.     if (verbose) {
  392.         buffer[6]='\0';
  393.         (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
  394.     }
  395.     if (debug)
  396.         dump(pos,buffer,6);
  397.     if (output) {
  398.         if (!strncmp((char *)buffer,"GIF87a",6))
  399.             buffer[4]='9';
  400.         (void)fwrite((void *)buffer,6,1,dest);
  401.     }
  402.  
  403.     /* Logical Screen Descriptor */
  404.     pos=ftell(src);
  405.     (void)fread((void *)lsd,7,1,src);
  406.     if (verbose) {
  407.         (void)fprintf(stderr,"Logical Screen Descriptor:\n");
  408.         (void)fprintf(stderr,"\tLogical Screen Width: %d pixels\n",readword(lsd));
  409.         (void)fprintf(stderr,"\tLogical Screen Height: %d pixels\n",readword(lsd+2));
  410.         (void)fprintf(stderr,"\tGlobal Color Table Flag: %s\n",readflag(lsd[4]&0x80));
  411.         (void)fprintf(stderr,"\tColor Resolution: %d bits\n",(lsd[4]&0x70>>4)+1);
  412.         if (lsd[4]&0x80) {
  413.             (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
  414.             (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
  415.             (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
  416.         }
  417.         if (lsd[6])
  418.             (void)fprintf(stderr,"\tPixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
  419.     }
  420.     if (debug)
  421.         dump(pos,lsd,7);
  422.  
  423.     /* Global Color Table */
  424.     gct_delay=FALSE;
  425.     if (lsd[4]&0x80) {
  426.         gct_size=2<<(lsd[4]&0x7);
  427.         pos=ftell(src);
  428.         (void)fread((void *)gct,gct_size,3,src);
  429.         if (go.index==RGB)
  430.             for(cnt=0;cnt<gct_size&&go.index==RGB;cnt++)
  431.                 if (gct[3*cnt]==go.red&&gct[3*cnt+1]==go.green&&gct[3*cnt+2]==go.blue)
  432.                     go.index=cnt;
  433.         if (go.index>=0) {
  434.             if (gn.index>=0) {
  435.                 gn.red=gct[3*gn.index];
  436.                 gn.green=gct[3*gn.index+1];
  437.                 gn.blue=gct[3*gn.index+2];
  438.             }
  439.             gct[3*go.index]=gn.red;
  440.             gct[3*go.index+1]=gn.green;
  441.             gct[3*go.index+2]=gn.blue;
  442.         }
  443.         if (bc.index==RGB)
  444.             for(cnt=0;cnt<gct_size&&bc.index==RGB;cnt++)
  445.                 if (gct[3*cnt]==bc.red&&gct[3*cnt+1]==bc.green&&gct[3*cnt+2]==bc.blue)
  446.                     bc.index=cnt;
  447.         if (bc.index>=0)
  448.             lsd[5]=bc.index;
  449.         if (tc.index==RGB)
  450.             for(cnt=0;cnt<gct_size&&tc.index==RGB;cnt++)
  451.                 if (gct[3*cnt]==tc.red&&gct[3*cnt+1]==tc.green&&gct[3*cnt+2]==tc.blue)
  452.                     tc.index=cnt;
  453.         if (tc.index==OTHER)
  454.             tc.index=lsd[5];
  455.         if (tn.index>=0) {
  456.             tn.red=gct[3*tn.index];
  457.             tn.green=gct[3*tn.index+1];
  458.             tn.blue=gct[3*tn.index+2];
  459.         }
  460.         if (tn.index!=NONE)
  461.             gct_delay=TRUE;
  462.     }
  463.     if (output)
  464.         (void)fwrite((void *)lsd,7,1,dest);
  465.     if (lsd[4]&0x80) {
  466.         if (list||verbose) {
  467.             (void)fprintf(stderr,"Global Color Table:\n");
  468.             for(cnt=0;cnt<gct_size;cnt++) {
  469.                 (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d",cnt,gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  470.                 (void)fprintf(stderr,", #%02x%02x%02x",gct[3*cnt],gct[3*cnt+1],gct[3*cnt+2]);
  471.                 for (rgbptr=root,cols=0;rgbptr;rgbptr=rgbptr->next)
  472.                     if (rgbptr->red==gct[3*cnt]&&rgbptr->green==gct[3*cnt+1]&&rgbptr->blue==gct[3*cnt+2])
  473.                         (void)fprintf(stderr,"%s%s",cols++?", ":" (",rgbptr->name);
  474.                 (void)fprintf(stderr,"%s\n",cols?")":"");
  475.             }
  476.         }
  477.         if (debug)
  478.             dump(pos,gct,gct_size*3);
  479.         if (output&&(!gct_delay))
  480.             (void)fwrite((void *)gct,gct_size,3,dest);
  481.     }
  482.  
  483.     gce_present=FALSE;
  484.     do {
  485.         pos=ftell(src);
  486.         (void)fread((void *)buffer,1,1,src);
  487.         switch (buffer[0]) {
  488.         case 0x2c:    /* Image Descriptor */
  489.             if (verbose)
  490.                 (void)fprintf(stderr,"Image Descriptor:\n");
  491.             (void)fread((void *)(buffer+1),9,1,src);
  492.             /* Write Graphic Control Extension */
  493.             if (tc.index>=0||gce_present) {
  494.                 if (!gce_present) {
  495.                     gce[0]=0;
  496.                     gce[1]=0;
  497.                     gce[2]=0;
  498.                 }
  499.                 if (tc.index>=0) {
  500.                     gce[0]|=0x01;    /* Set Transparent Color Flag */
  501.                     gce[3]=tc.index;    /* Set Transparent Color Index */
  502.                 }
  503.                 else if (gce[0]&0x01)
  504.                     tc.index=gce[3];    /* Remember Transparent Color Index */
  505.                 gce[4]=0;
  506.                 if (tc.index>=0&&(!(buffer[8]&0x80))) { /* Transparent Color Flag set and no Local Color Table */
  507.                     gct[3*tc.index]=tn.red;
  508.                     gct[3*tc.index+1]=tn.green;
  509.                     gct[3*tc.index+2]=tn.blue;
  510.                 }
  511.                 if (output&&gct_delay) {
  512.                     (void)fwrite((void *)gct,gct_size,3,dest);
  513.                     gct_delay=FALSE;
  514.                 }
  515.                 if (output) {
  516.                     (void)fputs("\041\371\004",dest);
  517.                     (void)fwrite((void *)gce,5,1,dest);
  518.                 }
  519.             }
  520.             if (output&&gct_delay) {
  521.                 if (verbose)
  522.                     (void)fprintf(stderr,"Warning: Global Color Table has not been modified as no Transparent Color Index has been set\n");
  523.                 (void)fwrite((void *)gct,gct_size,3,dest);
  524.                 gct_delay=FALSE;
  525.             }
  526.             /* Write Image Descriptor */
  527.             if (verbose) {
  528.                 (void)fprintf(stderr,"\tImage Left Position: %d pixels\n",readword(buffer+1));
  529.                 (void)fprintf(stderr,"\tImage Top Position: %d pixels\n",readword(buffer+3));
  530.                 (void)fprintf(stderr,"\tImage Width: %d pixels\n",readword(buffer+5));
  531.                 (void)fprintf(stderr,"\tImage Height: %d pixels\n",readword(buffer+7));
  532.                 (void)fprintf(stderr,"\tLocal Color Table Flag: %s\n",readflag(buffer[9]&0x80));
  533.                 (void)fprintf(stderr,"\tInterlace Flag: %s\n",readflag(buffer[9]&0x40));
  534.                 if (buffer[9]&0x80) {
  535.                     (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(buffer[9]&0x20));
  536.                     (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(buffer[9]&0x7));
  537.                 }
  538.             }
  539.             if (debug)
  540.                 dump(pos,buffer,10);
  541.             if (output)
  542.                 (void)fwrite((void *)buffer,10,1,dest);
  543.             /* Local Color Table */
  544.             if (buffer[8]&0x80) {
  545.                 size=2<<(buffer[8]&0x7);
  546.                 pos=ftell(src);
  547.                 (void)fread((void *)buffer,size,3,src);
  548.                 if (verbose) {
  549.                     (void)fprintf(stderr,"Local Color Table:\n");
  550.                     for(cnt=0;cnt<size;cnt++)
  551.                         (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
  552.                 }
  553.                 if (tc.index>=0) { /* Transparent Color Flag set */
  554.                     buffer[3*tc.index]=tn.red;
  555.                     buffer[3*tc.index+1]=tn.green;
  556.                     buffer[3*tc.index+2]=tn.blue;
  557.                 }
  558.                 if (debug)
  559.                     dump(pos,buffer,size*3);
  560.                 if (output)
  561.                     (void)fwrite((void *)buffer,size,3,dest);
  562.             }
  563.             /* Table Based Image Data */
  564.             pos=ftell(src);
  565.             (void)fread((void *)buffer,1,1,src);
  566.             if (verbose) {
  567.                 (void)fprintf(stderr,"Table Based Image Data:\n");
  568.                 (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
  569.             }
  570.             if (debug)
  571.                 dump(pos,buffer,1);
  572.             if (output)
  573.                 (void)fwrite((void *)buffer,1,1,dest);
  574.             transdata(src,dest);
  575.             gce_present=FALSE;
  576.             break;
  577.         case 0x3b:    /* Trailer */
  578.             if (verbose)
  579.                 (void)fprintf(stderr,"Trailer\n");
  580.             if (debug)
  581.                 dump(pos,buffer,1);
  582.             if (comment&&*comment&&output) {
  583.                 (void)fputs("\041\376",dest);
  584.                 writedata(dest,(unsigned char *)comment,strlen(comment));
  585.             }
  586.             if (output)
  587.                 (void)fwrite((void *)buffer,1,1,dest);
  588.             break;
  589.         case 0x21:    /* Extension */
  590.             (void)fread((void *)(buffer+1),1,1,src);
  591.             switch (buffer[1]) {
  592.             case 0x01:    /* Plain Text Extension */
  593.                 if (output&&gct_delay) {
  594.                     if (verbose)
  595.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Plain Text Extension\n");
  596.                     (void)fwrite((void *)gct,gct_size,3,dest);
  597.                     gct_delay=FALSE;
  598.                 }
  599.                 if (verbose)
  600.                     (void)fprintf(stderr,"Plain Text Extension\n");
  601.                 if (debug)
  602.                     dump(pos,buffer,2);
  603.                 if (output)
  604.                     (void)fwrite((void *)buffer,2,1,dest);
  605.                 transblock(src,dest);
  606.                 transdata(src,dest);
  607.                 break;
  608.             case 0xf9:    /* Graphic Control Extension */
  609.                 if (verbose)
  610.                     (void)fprintf(stderr,"Graphic Control Extension:\n");
  611.                 (void)fread((void *)(buffer+2),1,1,src);
  612.                 size=buffer[2];
  613.                 (void)fread((void *)gce,size,1,src);
  614.                 if (verbose) {
  615.                     (void)fprintf(stderr,"\tDisposal Method: %d ",gce[0]&0x1c>>2);
  616.                     switch (gce[0]&0x1c>>2) {
  617.                     case 0:
  618.                         (void)fprintf(stderr,"(no disposal specified)\n");
  619.                         break;
  620.                     case 1:
  621.                         (void)fprintf(stderr,"(do not dispose)\n");
  622.                         break;
  623.                     case 2:
  624.                         (void)fprintf(stderr,"(restore to background color)\n");
  625.                         break;
  626.                     case 3:
  627.                         (void)fprintf(stderr,"(restore to previous)\n");
  628.                         break;
  629.                     default:
  630.                         (void)fprintf(stderr,"(to be defined)\n");
  631.                     }
  632.                     (void)fprintf(stderr,"\tUser Input Flag: %s\n",readflag(gce[0]&0x2));
  633.                     (void)fprintf(stderr,"\tTransparent Color Flag: %s\n",readflag(gce[0]&0x1));
  634.                     (void)fprintf(stderr,"\tDelay Time: %d\n",readword(gce+1));
  635.                     if (gce[0]&0x1)
  636.                         (void)fprintf(stderr,"\tTransparent Color Index: %d\n",gce[3]);
  637.                 }
  638.                 if (debug) {
  639.                     dump(pos,buffer,3);
  640.                     dump(pos+3,gce,size);
  641.                 }
  642.                 pos=ftell(src);
  643.                 (void)fread((void *)buffer,1,1,src);
  644.                 if (debug)
  645.                     dump(pos,buffer,1);
  646.                 gce_present=TRUE;
  647.                 break;
  648.             case 0xfe:    /* Comment Extension */
  649.                 if (verbose)
  650.                 {
  651.                     (void)fprintf(stderr,"Comment Extension\n");
  652.                     dumpcomment(src);
  653.                 }
  654.                 if (debug)
  655.                     dump(pos,buffer,2);
  656.                 if (skipcomment)
  657.                     skipdata(src);
  658.                 else {
  659.                     if (output&&gct_delay) {
  660.                         if (verbose)
  661.                             (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Comment Extension\n");
  662.                         (void)fwrite((void *)gct,gct_size,3,dest);
  663.                         gct_delay=FALSE;
  664.                     }
  665.                     if (output)
  666.                         (void)fwrite((void *)buffer,2,1,dest);
  667.                     transdata(src,dest);
  668.                 }
  669.                 break;
  670.             case 0xff:    /* Application Extension */
  671.                 if (output&&gct_delay) {
  672.                     if (verbose)
  673.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to a Application Extension\n");
  674.                     (void)fwrite((void *)gct,gct_size,3,dest);
  675.                     gct_delay=FALSE;
  676.                 }
  677.                 if (verbose)
  678.                     (void)fprintf(stderr,"Application Extension\n");
  679.                 if (debug)
  680.                     dump(pos,buffer,2);
  681.                 if (output)
  682.                     (void)fwrite((void *)buffer,2,1,dest);
  683.                 transblock(src,dest);
  684.                 transdata(src,dest);
  685.                 break;
  686.             default:
  687.                 if (output&&gct_delay) {
  688.                     if (verbose)
  689.                         (void)fprintf(stderr,"Warning: Global Color Table has not been modified due to an unknown Extension\n");
  690.                     (void)fwrite((void *)gct,gct_size,3,dest);
  691.                     gct_delay=FALSE;
  692.                 }
  693.                 if (verbose)
  694.                     (void)fprintf(stderr,"Unknown label: 0x%02x\n",buffer[1]);
  695.                 if (debug)
  696.                     dump(pos,buffer,2);
  697.                 if (output)
  698.                     (void)fwrite((void *)buffer,2,1,dest);
  699.                 transblock(src,dest);
  700.                 transdata(src,dest);
  701.                 break;
  702.             }
  703.             break;
  704.         default:
  705.             (void)fprintf(stderr,"0x%08lx: Unknown extension 0x%02x!\n",ftell(src)-1,buffer[0]);
  706.             if (debug)
  707.                 dump(pos,buffer,1);
  708.             return(1);
  709.         }
  710.     } while (buffer[0]!=0x3b&&!feof(src));
  711.     return(buffer[0]==0x3b?SUCCESS:FAILURE);
  712. }
  713.  
  714.  
  715.  
  716. int getindex(c,arg)
  717. struct color    *c;
  718. char    *arg;
  719. {
  720.     struct entry    *ptr;
  721.  
  722.     if ('0'<=*arg&&*arg<='9')
  723.         c->index=atoi(arg);
  724.     else if (*arg=='#') {
  725.         if (strlen(arg)==4) {
  726.             c->index=RGB;
  727.             c->red=hex(arg[1])<<4;
  728.             c->green=hex(arg[2])<<4;
  729.             c->blue=hex(arg[3])<<4;
  730.         }
  731.         else if (strlen(arg)==7) {
  732.             c->index=RGB;
  733.             c->red=(hex(arg[1])<<4)+hex(arg[2]);
  734.             c->green=(hex(arg[3])<<4)+hex(arg[4]);
  735.             c->blue=(hex(arg[5])<<4)+hex(arg[6]);
  736.         }
  737.         else {
  738.             (void)fprintf(stderr,"%s: illegal color specification: %s\n",image,arg);
  739.             return(FAILURE);
  740.         }
  741.     }
  742.     else {
  743.         for (ptr=root;ptr&&c->index!=RGB;ptr=ptr->next)
  744.             if (!strcmp(ptr->name,arg)) {
  745.                 c->index=RGB;
  746.                 c->red=ptr->red;
  747.                 c->green=ptr->green;
  748.                 c->blue=ptr->blue;
  749.             }
  750.         if (c->index!=RGB) {
  751.             (void)fprintf(stderr,"%s: no such color: %s\n",image,arg);
  752.             return(FAILURE);
  753.         }
  754.     }
  755.     return(SUCCESS);
  756. }
  757.  
  758.  
  759.  
  760. void usage()
  761. {
  762.     (void)fprintf(stderr,"Usage: %s [-t color|-T] [-B color] [-b color] [-g oldcolor=newcolor] [-c comment|-C] [-l|-L|-V] [-o filename] [-e filename] [filename]\n",image);
  763.     (void)fprintf(stderr,"Convert any GIF file into a GIF89a, with the folloing changes possible:\n");
  764.     (void)fprintf(stderr,"-t Specify the transparent color\n");
  765.     (void)fprintf(stderr,"-T Index of the transparent color is the background color index\n");
  766.     (void)fprintf(stderr,"-B Specify the transparent color's new value\n");
  767.     (void)fprintf(stderr,"-b Specify the background color\n");
  768.     (void)fprintf(stderr,"-g Change a color in the global color table\n");
  769.     (void)fprintf(stderr,"-c Add a comment\n");
  770.     (void)fprintf(stderr,"-C Remove old comment\n");
  771.     (void)fprintf(stderr,"-l Only list the color table\n");
  772.     (void)fprintf(stderr,"-L Verbose output of GIFs contents\n");
  773.     (void)fprintf(stderr,"-V Verbose output while converting\n");
  774.     (void)fprintf(stderr,"-o Redirect stdout to a file\n");
  775.     (void)fprintf(stderr,"-e Redirect stderr to a file\n");
  776.     if (*rgb)
  777.         (void)fprintf(stderr,"Colors may be specified as index, as rgb.txt entry or in the #rrggbb form.\n");
  778.     else
  779.         (void)fprintf(stderr,"Colors may be specified as index or in the #rrggbb form.\n");
  780.     exit(1);
  781. }
  782.  
  783.  
  784. int main(argc,argv)
  785. int    argc;
  786. char    *argv[];
  787. {
  788.     int        c;
  789.     extern char    *optarg;
  790.     extern int    optind;
  791.     char        error[2*MAXPATHLEN+14],line[BUFSIZ],*ptr,*nptr,*oname,*ename;
  792.     struct entry    **next;
  793.     FILE        *src;
  794.     int        stat;
  795.  
  796. #ifdef OS2
  797.     ptr=getenv("XFILES");
  798.     if (ptr) {
  799.         rgb=(char *)malloc(strlen(ptr)+strlen(rgbtxt)+2);
  800.         (void)strcpy(rgb,ptr);
  801.         (void)strcat(rgb,"\\");
  802.         (void)strcat(rgb,rgbtxt);
  803.     }
  804. #endif /* OS2 */
  805.  
  806.     image=argv[0];
  807.     root=NULL;
  808.     if (*rgb)
  809.         if ((src=fopen(rgb,"r"))!=NULL) {
  810.             next= &root;
  811.             while (fgets(line,sizeof(line),src)) {
  812.                 *next=(struct entry *)malloc(sizeof(struct entry));
  813.                 for (ptr=line;strchr(" \t",*ptr);ptr++);
  814.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  815.                 *ptr++='\0';
  816.                 (*next)->red=atoi(nptr);
  817.                 for (;strchr(" \t",*ptr);ptr++);
  818.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  819.                 *ptr++='\0';
  820.                 (*next)->green=atoi(nptr);
  821.                 for (;strchr(" \t",*ptr);ptr++);
  822.                 for (nptr=ptr;!strchr(" \t",*ptr);ptr++);
  823.                 *ptr++='\0';
  824.                 (*next)->blue=atoi(nptr);
  825.                 for (;strchr(" \t",*ptr);ptr++);
  826.                 nptr=ptr;
  827.                 for (ptr=strchr(ptr,'\0');ptr>nptr&&strchr(" \t\r\n",*(ptr-1));ptr--);
  828.                 *ptr='\0';
  829.                 (void)strcpy((*next)->name=(char *)malloc(strlen(nptr)+1),nptr);
  830.                 (*next)->next=NULL;
  831.                 next= &(*next)->next;
  832.             }
  833.             (void)fclose(src);
  834.         }
  835.         else {
  836. #ifndef OS2_OR_MSDOS
  837.             (void)sprintf(error,"%s: cannot open %s",image,rgb);
  838.             perror(error);
  839.             return(FAILURE);
  840. #else /* OS2_OR_MSDOS */
  841.             *rgb='\0';
  842. #endif
  843.         }
  844.  
  845.     bc.index=NONE;
  846.     tc.index=NONE;
  847.     tn.index=NONE;
  848.     go.index=NONE;
  849.     gn.index=NONE;
  850.     comment=NULL;
  851.     skipcomment=FALSE;
  852.     verbose=FALSE;
  853.     output=TRUE;
  854.     debug=FALSE;
  855.     oname=NULL;
  856.     ename=NULL;
  857.     while ((c=getopt(argc,argv,"t:TB:b:g:c:ClLVDo:e:vh?")) != EOF)
  858.         switch ((char)c) {
  859.         case 'b':
  860.             if (getindex(&bc,optarg))
  861.                 return(FAILURE);
  862.             break;
  863.         case 't':
  864.             if (getindex(&tc,optarg))
  865.                 return(FAILURE);
  866.             break;
  867.         case 'T':
  868.             tc.index=OTHER;
  869.             break;
  870.         case 'B':
  871.             if (getindex(&tn,optarg))
  872.                 return(FAILURE);
  873.             break;
  874.         case 'g':
  875.             if ((ptr=strchr(optarg,'='))!=NULL) {
  876.                 *ptr++='\0';
  877.                 if (getindex(&go,optarg))
  878.                     return(FAILURE);
  879.                 if (getindex(&gn,ptr))
  880.                     return(FAILURE);
  881.             }
  882.             else
  883.                 usage();
  884.             break;
  885.         case 'c':
  886.             comment=optarg;
  887.             break;
  888.         case 'C':
  889.             skipcomment=TRUE;
  890.             break;
  891.         case 'l':
  892.             list=TRUE;
  893.             output=FALSE;
  894.             break;
  895.         case 'L':
  896.             verbose=TRUE;
  897.             output=FALSE;
  898.             break;
  899.         case 'V':
  900.             verbose=TRUE;
  901.             break;
  902.         case 'D':
  903.             debug=TRUE;
  904.             break;
  905.         case 'o':
  906.             oname=optarg;
  907.             break;
  908.         case 'e':
  909.             ename=optarg;
  910.             break;
  911.         case 'v':
  912.             (void)fprintf(stderr,"%s\n",sccsid+4);
  913.             (void)fprintf(stderr,"%s\n",copyright+4);
  914.             return(0);
  915.         case 'h':
  916.             (void)fprintf(stderr,"%s\n",sccsid+4);
  917.             (void)fprintf(stderr,"%s\n",copyright+4);
  918.         case '?':
  919.             usage();
  920.         }
  921.     if (optind+1<argc||(bc.index==NONE&&tc.index==NONE&&tn.index==NONE&&gn.index==NONE&&comment==NULL&&!skipcomment&&!list&&!verbose))
  922.         usage();
  923.  
  924.     if (oname&&freopen(oname,"wb",stdout)==NULL) {
  925.         (void)sprintf(error,"%s: cannot open %s",image,oname);
  926.         perror(error);
  927.         return(FAILURE);
  928.     }
  929.  
  930.     if (ename&&freopen(ename,"wb",stderr)==NULL) {
  931.         (void)sprintf(error,"%s: cannot open %s",image,ename);
  932.         perror(error);
  933.         return(FAILURE);
  934.     }
  935.  
  936. #ifdef OS2_OR_MSDOS
  937. #ifdef MSDOS
  938.     if(oname==NULL&&(stdout->flags&_F_TERM)==0&&setmode(fileno(stdout),O_BINARY)!=0) {
  939. #endif /* MSDOS */
  940. #ifdef OS2
  941.     if(oname==NULL&&!freopen("", "wb", stdout)) {
  942. #endif /* OS2 */
  943.         (void)fprintf(stderr,"%s: can't set stdout's mode to binary\n",image);
  944.         exit(2);
  945.     }
  946. #ifdef MSDOS
  947.     if(optind==argc&&(stdin->flags&_F_TERM)==0&&setmode(fileno(stdin),O_BINARY)) {
  948. #endif /* MSDOS */
  949. #ifdef OS2
  950.     if(optind==argc&&!freopen("", "rb", stdin)) {
  951. #endif /* OS2 */
  952.         (void)fprintf(stderr,"%s: can't set stdin's mode to binary\n",image);
  953.         exit(2);
  954.     }
  955. #endif /* OS2_OR_MSDOS */
  956.  
  957.     if (optind<argc)
  958.         if (strcmp(argv[optind],"-"))
  959.             if ((src=fopen(argv[optind],"rb"))!=NULL) {
  960.                 stat=giftrans(src,stdout);
  961.                 (void)fclose(src);
  962.             }
  963.             else {
  964.                 (void)sprintf(error,"%s: cannot open %s",image,argv[optind]);
  965.                 perror(error);
  966.                 return(FAILURE);
  967.             }
  968.         else
  969.             stat=giftrans(stdin,stdout);
  970.     else
  971.         stat=giftrans(stdin,stdout);
  972.  
  973.     (void)fclose(stdout);
  974.     (void)fclose(stderr);
  975.     return(stat);
  976. }
  977.